package com.ivan.toolkit.common;

import java.awt.Image;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

public class Ajax {
	
	private static final String DefaultHome = "http://localhost:8080/emc";

	private CloseableHttpClient httpClient = null;

	private String home = DefaultHome;

	private String path = "";

	private String charset = "UTF-8";
	
	private boolean radom = true;
	
	private int connectTimout = 5000;
	
	private int socketTimeout = 5000;

	List<NameValuePair> pairs = new LinkedList<NameValuePair>();
	
	public Ajax() {
		super();
	}

	public CloseableHttpClient getHttpClient() {
		return httpClient;
	}

	public void setHttpClient(CloseableHttpClient httpClient) {
		this.httpClient = httpClient;
	}

	public String getHome() {
		return home;
	}

	public void setHome(String home) {
		this.home = home;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	public boolean isRadom() {
		return radom;
	}

	public void setRadom(boolean radom) {
		this.radom = radom;
	}

	public int getConnectTimout() {
		return connectTimout;
	}

	public void setConnectTimout(int connectTimout) {
		this.connectTimout = connectTimout;
	}

	public int getSocketTimeout() {
		return socketTimeout;
	}

	public void setSocketTimeout(int socketTimeout) {
		this.socketTimeout = socketTimeout;
	}

	public void addParameter(String key, String value) {
		if(key == null || key.isEmpty()) {
			return;
		}
		
		removeParameter(key);
		
		pairs.add(new BasicNameValuePair(key, value));
	}
	
	public void addParameter(String key, boolean value) {
		addParameter(key, String.valueOf(value));
	}
	
	public void addParameter(String key, long value) {
		addParameter(key, String.valueOf(value));
	}	
	
	public void addParameter(String key, int value) {
		addParameter(key, String.valueOf(value));
	}
	
	public void addParameter(String key, float value) {
		addParameter(key, String.valueOf(value));
	}
	
	public void addParameter(String key, double value) {
		addParameter(key, String.valueOf(value));
	}
	
	NameValuePair findParameter(String key) {
		for(NameValuePair pair : pairs) {
			if(pair.getName().equals(key)) {
				return pair;
			}
		}
		return null;
	}
	
	public void removeParameter(String key) {
		NameValuePair pair = findParameter(key);
		if(pair != null) {
			pairs.remove(pair);
		}
	}

	public void clearParameter() {
		pairs.clear();
	}
	
	private String processArray(String string) {
		
		if(string == null || string.isEmpty()) {
			return string;
		}
		
		if(string.startsWith("[")) {
			return "{array:" + string + "}";
		} else {
			return string;
		}
		
	}
	
	private List<NameValuePair> getPairs() {
		if(radom) {
			this.addParameter("_t_", Long.toString(System.currentTimeMillis()));
		} else {
			this.removeParameter("_t_");
		}
		return pairs;
	}
	
	private void timeoutPrepare(HttpRequestBase request) {
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(this.socketTimeout)
				.setConnectTimeout(this.connectTimout)
				.build();
		request.setConfig(requestConfig);
	}

	public JSONObject doGet() {

		try {

			String url = home + path;

			if (!pairs.isEmpty()) {
				url += "?"
						+ EntityUtils.toString(new UrlEncodedFormEntity(getPairs(),
								charset));
			}

			HttpGet httpGet = new HttpGet(url);
			timeoutPrepare(httpGet);
			
			CloseableHttpResponse response = httpClient.execute(httpGet);

			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				httpGet.abort();
				throw new RuntimeException("HttpClient,error status code :"
						+ statusCode);
			}

			HttpEntity entity = response.getEntity();
			String result = null;
			if (entity != null) {
				result = EntityUtils.toString(entity, charset);
			}

			EntityUtils.consume(entity);
			response.close();

			return new JSONObject(processArray(result));

		} catch (Exception e) {

			e.printStackTrace();

		}

		return null;
	}

	public JSONObject doPost() throws Exception {

		try {

			String url = home + path;

			HttpPost httpPost = new HttpPost(url);
			if (!pairs.isEmpty()) {
				httpPost.setEntity(new UrlEncodedFormEntity(getPairs(), charset));
			}
			
			timeoutPrepare(httpPost);

			CloseableHttpResponse response = httpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				httpPost.abort();
				throw new RuntimeException("HttpClient,error status code :"
						+ statusCode);
			}

			HttpEntity entity = response.getEntity();
			String result = null;
			if (entity != null) {
				result = EntityUtils.toString(entity, charset);
			}

			EntityUtils.consume(entity);
			response.close();
			
			return new JSONObject(processArray(result));

		} catch (Exception e) {
			throw e;
		}

	}
	
	public JSONObject doUpload(File file) {
		return doUpload(file, null);
	}

	public JSONObject doUpload(File file, String target) {

		if (file == null || !file.exists()) {
			throw new RuntimeException("Ajax.doUpload(), invalid file.");
		}

		try {

			String url = home + path;

			HttpPost httpPost = new HttpPost(url);
			
			if(target == null) {
				target = file.getName();
			}

			FileBody bin = new FileBody(file, ContentType.DEFAULT_BINARY, target);

			MultipartEntityBuilder meb = MultipartEntityBuilder.create();
			meb.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
			meb.addPart("multipartFile", bin);
			for(NameValuePair pair : pairs) {
				meb.addPart(pair.getName(), new StringBody(pair.getValue(), ContentType.create("text/plain", Charset.forName(charset))));
			}
			meb.setCharset(Charset.forName(charset));
			
			HttpEntity reqEntity = meb.build();
			
			httpPost.setEntity(reqEntity);

			CloseableHttpResponse response = httpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				httpPost.abort();
				throw new RuntimeException("HttpClient,error status code :"
						+ statusCode);
			}

			HttpEntity entity = response.getEntity();
			String result = null;
			if (entity != null) {
				result = EntityUtils.toString(entity, charset);
			}

			EntityUtils.consume(entity);
			response.close();

			return new JSONObject(result);

		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;

	}
	
	public Object doDownload() throws Exception{

			String url = home + path;

			HttpPost httpPost = new HttpPost(url);
			if (!pairs.isEmpty()) {
				httpPost.setEntity(new UrlEncodedFormEntity(getPairs(), charset));
			}

			CloseableHttpResponse response = httpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				httpPost.abort();
				throw new RuntimeException("HttpClient,error status code :"
						+ statusCode);
			}

			HttpEntity entity = response.getEntity();
			if (entity == null) {
				throw new RuntimeException("HttpClient,error null entity.");
			}
			
			ObjectInputStream ois = new ObjectInputStream(entity.getContent());
			
			return ois.readObject();
	}
	
	public byte[] doLoadData() {
		try {
			
			String url = home + path;
	
			HttpPost httpPost = new HttpPost(url);
			if (!pairs.isEmpty()) {
				httpPost.setEntity(new UrlEncodedFormEntity(getPairs(), charset));
			}
	
			CloseableHttpResponse response = httpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				httpPost.abort();
				throw new RuntimeException("HttpClient,error status code :"
						+ statusCode);
			}
			
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				
				int BUFFER_SIZE = 4096;
				InputStream in = entity.getContent();
				ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		        byte[] data = new byte[BUFFER_SIZE];
		        int count = -1;
		        while((count = in.read(data,0,BUFFER_SIZE)) != -1)
		            outStream.write(data, 0, count);
		         
		        data = null;
		        return outStream.toByteArray();
			}
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public Image doDownloadImage() {
		
		try {
		
			String url = home + path;
	
			HttpPost httpPost = new HttpPost(url);
			if (!pairs.isEmpty()) {
				httpPost.setEntity(new UrlEncodedFormEntity(getPairs(), charset));
			}
	
			CloseableHttpResponse response = httpClient.execute(httpPost);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				httpPost.abort();
				throw new RuntimeException("HttpClient,error status code :"
						+ statusCode);
			}
			
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				return ImageIO.read(entity.getContent());
			}
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
		
	}

	public static void main(String[] args) {

		Ajax ajax = new Ajax();
		ajax.setHttpClient(HttpClients.createDefault());
		ajax.setPath("/center/page.do");
		ajax.addParameter("page", "0");
		ajax.addParameter("size", "10");

		JSONObject json = ajax.doGet();
		System.out.println(json.toString());

		try {
			json = ajax.doPost();
			System.out.println(json.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
